package com.wust.smartcity.demo.server.common.aspect;


import com.wust.smartcity.common.annotations.EnableDistributedCaching;
import com.wust.smartcity.common.annotations.EnableLocalCaching;
import com.wust.smartcity.common.CacheAspectBase;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

/**
 * 缓存拦截器，先查缓存再查数据库
 */
@Aspect
@Component
public class CacheAspect extends CacheAspectBase {

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.selectByPrimaryKey(..))")
    private void selectByPrimaryKey() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.existsWithPrimaryKey(..))")
    private void existsWithPrimaryKey() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.selectOne(..))")
    private void selectOne() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.selectOneByExample(..))")
    private void selectOneByExample() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.insert(..))")
    private void insert() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.insertList(..))")
    private void insertList() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.updateByPrimaryKey(..))")
    private void updateByPrimaryKey() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.updateByPrimaryKeySelective(..))")
    private void updateByPrimaryKeySelective() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.updateByExample(..))")
    private void updateByExample() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.deleteByPrimaryKey(..))")
    private void deleteByPrimaryKey() {
    }

    @Pointcut("execution(* com.wust.smartcity.common.dao.IBaseMapper.deleteByExample(..))")
    private void deleteByExample() {
    }

    @Autowired
    private Environment environment;

    @Around("selectByPrimaryKey() || existsWithPrimaryKey() || selectOne() || selectOneByExample()")
    public Object around(ProceedingJoinPoint jp) throws Throwable {
        Signature sig = jp.getSignature();
        if (sig instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) sig;
            Method currentMethod = jp.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());

            // 是否开启本地缓存
            Object enableCachingObj = currentMethod.getAnnotation(EnableLocalCaching.class);

            // 是否开启分布式缓存
            Object enableDistributedCacheObj = currentMethod.getAnnotation(EnableDistributedCaching.class);

            if(enableCachingObj != null && enableDistributedCacheObj != null) {
                return super.around(jp,3);
            }else if(enableDistributedCacheObj != null){
                return super.around(jp,2);
            }else if(enableCachingObj != null){
                return super.around(jp,1);
            }
        }
        return jp.proceed();
    }

    @AfterReturning("insert() || insertList() || updateByPrimaryKey() || updateByPrimaryKeySelective() || updateByExample() || deleteByPrimaryKey() || deleteByExample()")
    public void afterReturning(JoinPoint jp) throws Throwable {
        Signature sig = jp.getSignature();
        if (sig instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) sig;
            Method currentMethod = jp.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());

            // 是否开启本地缓存
            Object enableLocalCachingObj = currentMethod.getAnnotation(EnableLocalCaching.class);

            // 是否开启分布式缓存
            Object enableDistributedCacheObj = currentMethod.getAnnotation(EnableDistributedCaching.class);

            if(enableLocalCachingObj != null && enableDistributedCacheObj != null) {
                super.afterReturning(jp,3);
            }else if(enableDistributedCacheObj != null){
                super.afterReturning(jp,2);
            }else if(enableLocalCachingObj != null){
                super.afterReturning(jp,1);
            }
        }
    }
}
